﻿using System;
using System.Collections.Generic;
using System.Linq;
using MMD.VMD;
using UnityEngine;

namespace WzhAddon
{
    public class VMDHSConverter
    {
        private abstract class CustomKeyframe<Type>
        {
            public float time { get; set; }
            public Type value { get; set; }
            public CustomKeyframe(float time, Type value)
            {
                this.time = time;
                this.value = value;
            }
        }

        private class FloatKeyframe : CustomKeyframe<float>
        {
            public FloatKeyframe(float time, float value) : base(time, value) { }

            public static FloatKeyframe Lerp(FloatKeyframe from, FloatKeyframe to, Vector2 t)
            {
                return new FloatKeyframe(Mathf.Lerp(from.time, to.time, t.x), Mathf.Lerp(from.value, to.value, t.y));
            }

            public static void AddBezierKeyframes(byte[] interpolation, int type, FloatKeyframe prev_keyframe, FloatKeyframe cur_keyframe, int interpolationQuality, ref List<FloatKeyframe> keyframes, ref int index)
            {
                if (prev_keyframe == null || IsLinear(interpolation, type))
                {
                    keyframes.Add(cur_keyframe);
                    index = keyframes.Count();
                    return;
                }

                Vector2 bezierHandle = GetBezierHandle(interpolation, type, 0);
                Vector2 bezierHandle2 = GetBezierHandle(interpolation, type, 1);
                for (int i = 0; i < interpolationQuality; i++)
                {
                    float t = (float)(i + 1) / (float)interpolationQuality;
                    Vector2 t2 = SampleBezier(bezierHandle, bezierHandle2, t);
                    keyframes.Add(Lerp(prev_keyframe, cur_keyframe, t2));
                    index = keyframes.Count();
                }
            }
        }

        private class QuaternionKeyframe : CustomKeyframe<Quaternion>
        {
            public QuaternionKeyframe(float time, Quaternion value)
                : base(time, value)
            {
            }

            public static QuaternionKeyframe Lerp(QuaternionKeyframe from, QuaternionKeyframe to, Vector2 t)
            {
                return new QuaternionKeyframe(Mathf.Lerp(from.time, to.time, t.x), Quaternion.Slerp(from.value, to.value, t.y));
            }

            public static void AddBezierKeyframes(byte[] interpolation, int type, QuaternionKeyframe prev_keyframe, QuaternionKeyframe cur_keyframe, int interpolationQuality, ref QuaternionKeyframe[] keyframes, ref int index)
            {
                if (prev_keyframe == null || IsLinear(interpolation, type))
                {
                    keyframes[index++] = cur_keyframe;
                    return;
                }

                Vector2 bezierHandle = GetBezierHandle(interpolation, type, 0);
                Vector2 bezierHandle2 = GetBezierHandle(interpolation, type, 1);
                for (int i = 0; i < interpolationQuality; i++)
                {
                    float t = (float)(i + 1) / (float)interpolationQuality;
                    Vector2 t2 = SampleBezier(bezierHandle, bezierHandle2, t);
                    keyframes[index++] = Lerp(prev_keyframe, cur_keyframe, t2);
                }
            }
        }

        private Dictionary<string, string> boneNameMap;

        private Dictionary<string, BoneAdjustment> boneAdjustment;

        public float scale = 1f;

        public Vector3 centerBasePos;

        private Vector3 hipCenterDiff;

        private Vector3 hipPositionDiff;

        private bool isBaseAll;

        private bool isUseSlot;

        private bool isWaistLeg;

        private Dictionary<string, AnimationCurve> dicWaist;

        public HSModelBaselineData HSModelBaseline;

        private AnimationCurve centerXCurve;

        private AnimationCurve centerYCurve;

        private AnimationCurve centerZCurve;

        private AnimationCurve centerWCurve;

        private const int TangentModeBothLinear = 21;

        public VMDHSConverter(Dictionary<string, string> boneNameMap, HSModelBaselineData hsModelBaseline, Dictionary<string, BoneAdjustment> boneAdjustment, float scale, Vector3 centerBasePos, Vector3 hipPositionAdjust, Vector3 slotAdjust, bool isBaseAll, bool isUseSlot, bool isWaistLeg)
        {
            HSModelBaseline = hsModelBaseline;
            this.boneNameMap = boneNameMap;
            this.boneAdjustment = boneAdjustment;
            this.centerBasePos = hsModelBaseline.centerPos / scale;
            this.scale = scale;
            hipCenterDiff = (hsModelBaseline.hipsPos - hsModelBaseline.slotPos) / scale + hipPositionAdjust;
            hipPositionDiff = (hsModelBaseline.slotPos - hsModelBaseline.centerPos) / scale;
            this.isBaseAll = isBaseAll;
            this.isUseSlot = isUseSlot;
            this.isWaistLeg = isWaistLeg;
        }

        public AnimationClip CreateAnimationClip(VMDFormat format, GameObject assign_pmd, int interpolationQuality)
        {
            AnimationClip animationClip = new AnimationClip();
            animationClip.name = format.clip_name;
            animationClip.legacy = true;
            AddBoneMotion(format, interpolationQuality);
            Dictionary<string, string> dic = new Dictionary<string, string>();
            FullSearchBonePath(assign_pmd.transform, assign_pmd.transform, dic);
            Dictionary<string, GameObject> obj = new Dictionary<string, GameObject>();
            FullEntryBoneAnimation(format, animationClip, dic, obj, interpolationQuality);
            return animationClip;
        }

        private void AddBoneMotion(VMDFormat format, int interpolationQuality)
        {
            if (isUseSlot)
            {
                dicWaist = null;
                if (format.motion_list.motion.ContainsKey("腰") && isWaistLeg)
                {
                    dicWaist = CollectCurve(format, "腰", interpolationQuality);
                    List<VMDFormat.Motion> list = format.motion_list.motion["腰"];
                    for (int i = 0; i < list.Count; i++)
                    {
                        list[i].location += hipCenterDiff;
                    }
                }
                else
                {
                    VMDFormat.Motion item = new VMDFormat.Motion("腰", hipCenterDiff, Quaternion.identity);
                    List<VMDFormat.Motion> list2 = new List<VMDFormat.Motion>();
                    list2.Add(item);
                    format.motion_list.motion["腰"] = list2;
                }
            }
            else
            {
                if (format.motion_list.motion.ContainsKey("センター"))
                {
                    format.motion_list.motion["腰"] = format.motion_list.motion["センター"];
                    format.motion_list.motion.Remove("センター");
                }

                if (format.motion_list.motion.ContainsKey("グルーブ"))
                {
                    format.motion_list.motion.Remove("グルーブ");
                }
            }
        }

        private static Vector2 GetBezierHandle(byte[] interpolation, int type, int ab)
        {
            return new Vector2((int)interpolation[ab * 8 + type], (int)interpolation[ab * 8 + 4 + type]) / 127f;
        }

        private static Vector2 SampleBezier(Vector2 bezierHandleA, Vector2 bezierHandleB, float t)
        {
            Vector2 zero = Vector2.zero;
            Vector2 b = new Vector2(1f, 1f);
            Vector2 a = Vector2.Lerp(zero, bezierHandleA, t);
            Vector2 vector = Vector2.Lerp(bezierHandleA, bezierHandleB, t);
            Vector2 b2 = Vector2.Lerp(bezierHandleB, b, t);
            Vector2 a2 = Vector2.Lerp(a, vector, t);
            Vector2 b3 = Vector2.Lerp(vector, b2, t);
            return Vector2.Lerp(a2, b3, t);
        }

        private static bool IsLinear(byte[] interpolation, int type)
        {
            byte num = interpolation[type];
            byte b = interpolation[4 + type];
            byte b2 = interpolation[8 + type];
            byte b3 = interpolation[12 + type];
            if (num == b)
            {
                return b2 == b3;
            }

            return false;
        }

        private int GetKeyframeCount(List<VMDFormat.Motion> mlist, int type, int interpolationQuality)
        {
            int num = 0;
            for (int i = 0; i < mlist.Count; i++)
            {
                num = ((i <= 0 || IsLinear(mlist[i].interpolation, type)) ? (num + 1) : (num + interpolationQuality));
            }

            return num;
        }

        private void AddDummyKeyframe(ref Keyframe[] keyframes)
        {
            if (keyframes.Length == 1)
            {
                Keyframe[] array = new Keyframe[2]
                {
                    keyframes[0],
                    keyframes[0]
                };
                int num = 1;
                array[num].time += 1.66666669E-05f;
                array[0].outTangent = 0f;
                array[1].inTangent = 0f;
                keyframes = array;
            }
        }

        private float GetLinearTangentForPosition(Keyframe from_keyframe, Keyframe to_keyframe)
        {
            return (to_keyframe.value - from_keyframe.value) / (to_keyframe.time - from_keyframe.time);
        }

        private float Mod360(float angle)
        {
            if (angle >= 0f)
            {
                return angle;
            }

            return angle + 360f;
        }

        private float GetLinearTangentForRotation(Keyframe from_keyframe, Keyframe to_keyframe)
        {
            float num = Mod360(to_keyframe.value);
            float num2 = Mod360(from_keyframe.value);
            float num3 = Mod360(num - num2);
            if (num3 < 180f)
            {
                return num3 / (to_keyframe.time - from_keyframe.time);
            }

            return (num3 - 360f) / (to_keyframe.time - from_keyframe.time);
        }

        private Dictionary<string, Keyframe[]> ToKeyframesForRotation(QuaternionKeyframe[] custom_keys, ref Keyframe[] rx_keys, ref Keyframe[] ry_keys, ref Keyframe[] rz_keys)
        {
            rx_keys = new Keyframe[custom_keys.Length];
            ry_keys = new Keyframe[custom_keys.Length];
            rz_keys = new Keyframe[custom_keys.Length];
            Keyframe[] keyframes = new Keyframe[custom_keys.Length];
            Keyframe[] keyframes2 = new Keyframe[custom_keys.Length];
            Keyframe[] keyframes3 = new Keyframe[custom_keys.Length];
            Keyframe[] keyframes4 = new Keyframe[custom_keys.Length];
            Dictionary<string, Keyframe[]> dictionary = new Dictionary<string, Keyframe[]>();
            Quaternion a = Quaternion.identity;
            for (int i = 0; i < custom_keys.Length; i++)
            {
                Vector3 eulerAngles = custom_keys[i].value.eulerAngles;
                rx_keys[i] = new Keyframe(custom_keys[i].time, eulerAngles.x);
                ry_keys[i] = new Keyframe(custom_keys[i].time, eulerAngles.y);
                rz_keys[i] = new Keyframe(custom_keys[i].time, eulerAngles.z);
                rx_keys[i].tangentMode = 21;
                ry_keys[i].tangentMode = 21;
                rz_keys[i].tangentMode = 21;
                if (i > 0)
                {
                    float linearTangentForRotation = GetLinearTangentForRotation(rx_keys[i - 1], rx_keys[i]);
                    float linearTangentForRotation2 = GetLinearTangentForRotation(ry_keys[i - 1], ry_keys[i]);
                    float linearTangentForRotation3 = GetLinearTangentForRotation(rz_keys[i - 1], rz_keys[i]);
                    rx_keys[i - 1].outTangent = linearTangentForRotation;
                    ry_keys[i - 1].outTangent = linearTangentForRotation2;
                    rz_keys[i - 1].outTangent = linearTangentForRotation3;
                    rx_keys[i].inTangent = linearTangentForRotation;
                    ry_keys[i].inTangent = linearTangentForRotation2;
                    rz_keys[i].inTangent = linearTangentForRotation3;
                }

                Quaternion quaternion = Quaternion.Euler(eulerAngles);
                if (i > 0)
                {
                    quaternion = Quaternion.Slerp(a, quaternion, 0.9999f);
                }

                float time = custom_keys[i].time;
                keyframes[i] = new Keyframe(time, quaternion.x);
                keyframes2[i] = new Keyframe(time, quaternion.y);
                keyframes3[i] = new Keyframe(time, quaternion.z);
                keyframes4[i] = new Keyframe(time, quaternion.w);
                keyframes[i].tangentMode = 21;
                keyframes2[i].tangentMode = 21;
                keyframes3[i].tangentMode = 21;
                keyframes4[i].tangentMode = 21;
                if (i > 0)
                {
                    float linearTangentForPosition = GetLinearTangentForPosition(keyframes[i - 1], keyframes[i]);
                    float linearTangentForPosition2 = GetLinearTangentForPosition(keyframes2[i - 1], keyframes2[i]);
                    float linearTangentForPosition3 = GetLinearTangentForPosition(keyframes3[i - 1], keyframes3[i]);
                    float linearTangentForPosition4 = GetLinearTangentForPosition(keyframes4[i - 1], keyframes4[i]);
                    keyframes[i - 1].outTangent = linearTangentForPosition;
                    keyframes2[i - 1].outTangent = linearTangentForPosition2;
                    keyframes3[i - 1].outTangent = linearTangentForPosition3;
                    keyframes4[i - 1].outTangent = linearTangentForPosition4;
                    keyframes[i].inTangent = linearTangentForPosition;
                    keyframes2[i].inTangent = linearTangentForPosition2;
                    keyframes3[i].inTangent = linearTangentForPosition3;
                    keyframes4[i].inTangent = linearTangentForPosition4;
                }

                a = quaternion;
            }

            AddDummyKeyframe(ref rx_keys);
            AddDummyKeyframe(ref ry_keys);
            AddDummyKeyframe(ref rz_keys);
            AddDummyKeyframe(ref keyframes);
            AddDummyKeyframe(ref keyframes2);
            AddDummyKeyframe(ref keyframes3);
            AddDummyKeyframe(ref keyframes4);
            dictionary.Add("localRotation.x", keyframes);
            dictionary.Add("localRotation.y", keyframes2);
            dictionary.Add("localRotation.z", keyframes3);
            dictionary.Add("localRotation.w", keyframes4);
            return dictionary;
        }

        private void CreateKeysForRotation(VMDFormat format, AnimationClip clip, string current_bone, string bone_path, int interpolationQuality)
        {
            try
            {
                if (!boneNameMap.ContainsKey(current_bone))
                {
                    return;
                }

                string text = boneNameMap[current_bone];
                if (!format.motion_list.motion.ContainsKey(text))
                {
                    Console.WriteLine("bone {0}/{1} not found in motionlist", text, current_bone);
                    return;
                }

                if (format.motion_list.motion[text].Count == 0)
                {
                    Console.WriteLine("bone {0}/{1} count = 0", text, current_bone);
                    return;
                }

                Dictionary<string, AnimationCurve> dictionary = null;
                bool flag = false;
                if (text == "右足" || text == "左足")
                {
                    flag = true;
                }

                if (text == "右足ＩＫ" || text == "左足ＩＫ")
                {
                    string boneName = text.Substring(0, 2) + "IK親";
                    dictionary = CollectCurve(format, boneName, interpolationQuality);
                }

                BoneAdjustment boneAdjustment = null;
                if (this.boneAdjustment.ContainsKey(current_bone))
                {
                    boneAdjustment = this.boneAdjustment[current_bone];
                }

                List<VMDFormat.Motion> list = format.motion_list.motion[text];
                QuaternionKeyframe[] keyframes = new QuaternionKeyframe[GetKeyframeCount(list, 3, interpolationQuality)];
                QuaternionKeyframe prev_keyframe = null;
                int index = 0;
                Quaternion a = Quaternion.identity;
                for (int i = 0; i < list.Count; i++)
                {
                    float time = (float)list[i].flame_no / 30f;
                    Quaternion quaternion = list[i].rotation;
                    if (dictionary != null)
                    {
                        AnimationCurve value = null;
                        dictionary.TryGetValue("localEulerAngles.x", out value);
                        AnimationCurve value2 = null;
                        dictionary.TryGetValue("localEulerAngles.y", out value2);
                        AnimationCurve value3 = null;
                        dictionary.TryGetValue("localEulerAngles.z", out value3);
                        if (value != null && value2 != null && value3 != null)
                        {
                            Quaternion quaternion2 = Quaternion.Euler(value.Evaluate(time), value2.Evaluate(time), value3.Evaluate(time));
                            quaternion *= quaternion2;
                        }
                    }

                    if (flag && dicWaist != null && isWaistLeg)
                    {
                        AnimationCurve value4 = null;
                        dicWaist.TryGetValue("localEulerAngles.x", out value4);
                        AnimationCurve value5 = null;
                        dicWaist.TryGetValue("localEulerAngles.y", out value5);
                        AnimationCurve value6 = null;
                        dicWaist.TryGetValue("localEulerAngles.z", out value6);
                        if (value4 != null && value5 != null && value6 != null)
                        {
                            Quaternion quaternion3 = Quaternion.Euler(0f - value4.Evaluate(time), 0f - value5.Evaluate(time), 0f - value6.Evaluate(time));
                            quaternion *= quaternion3;
                        }
                    }

                    if (boneAdjustment != null)
                    {
                        quaternion = boneAdjustment.GetAdjustedRotation(quaternion);
                    }

                    if (i != 0)
                    {
                        quaternion = Quaternion.Slerp(a, quaternion, 0.99999f);
                    }

                    quaternion = new Quaternion(0f - quaternion.x, quaternion.y, 0f - quaternion.z, quaternion.w);
                    QuaternionKeyframe quaternionKeyframe = new QuaternionKeyframe(time, quaternion);
                    QuaternionKeyframe.AddBezierKeyframes(list[i].interpolation, 3, prev_keyframe, quaternionKeyframe, interpolationQuality, ref keyframes, ref index);
                    prev_keyframe = quaternionKeyframe;
                    a = quaternion;
                }

                Keyframe[] rx_keys = null;
                Keyframe[] ry_keys = null;
                Keyframe[] rz_keys = null;
                Dictionary<string, Keyframe[]> dictionary2 = ToKeyframesForRotation(keyframes, ref rx_keys, ref ry_keys, ref rz_keys);
                new AnimationCurve(rx_keys);
                new AnimationCurve(ry_keys);
                new AnimationCurve(rz_keys);
                AnimationCurve curve = new AnimationCurve(dictionary2["localRotation.x"]);
                AnimationCurve curve2 = new AnimationCurve(dictionary2["localRotation.y"]);
                AnimationCurve curve3 = new AnimationCurve(dictionary2["localRotation.z"]);
                AnimationCurve curve4 = new AnimationCurve(dictionary2["localRotation.w"]);
                clip.SetCurve(bone_path, typeof(Transform), "localRotation.x", curve);
                clip.SetCurve(bone_path, typeof(Transform), "localRotation.y", curve2);
                clip.SetCurve(bone_path, typeof(Transform), "localRotation.z", curve3);
                clip.SetCurve(bone_path, typeof(Transform), "localRotation.w", curve4);
                if (text == "センター")
                {
                    centerXCurve = curve;
                    centerYCurve = curve2;
                    centerZCurve = curve3;
                    centerWCurve = curve4;
                }
            }
            catch (KeyNotFoundException)
            {
            }
        }

        private Keyframe[] ToKeyframesForLocation(FloatKeyframe[] custom_keys)
        {
            Keyframe[] keyframes = new Keyframe[custom_keys.Length];
            for (int i = 0; i < custom_keys.Length; i++)
            {
                keyframes[i] = new Keyframe(custom_keys[i].time, custom_keys[i].value);
                keyframes[i].tangentMode = 21;
                if (i > 0)
                {
                    float linearTangentForPosition = GetLinearTangentForPosition(keyframes[i - 1], keyframes[i]);
                    keyframes[i - 1].outTangent = linearTangentForPosition;
                    keyframes[i].inTangent = linearTangentForPosition;
                }
            }

            AddDummyKeyframe(ref keyframes);
            return keyframes;
        }

        private void CreateKeysForLocation(VMDFormat format, AnimationClip clip, string current_bone, string bone_path, int interpolationQuality, GameObject current_obj = null)
        {
            try
            {
                if (!boneNameMap.ContainsKey(current_bone)) return;
                string text = boneNameMap[current_bone];
                if (!format.motion_list.motion.ContainsKey(text))
                {
                    Console.WriteLine("bone {0} / {1} not found in motionlist", text, current_bone);
                    return;
                }

                if (format.motion_list.motion[text].Count == 0)
                {
                    Console.WriteLine("bone {0}/{1} count = 0", text, current_bone);
                    return;
                }

                if (format.motion_list.motion[text].Count == 1 && text != "腰" && format.motion_list.motion[text][0].location == Vector3.zero)
                {
                    Console.WriteLine("bone {0}/{1} location always zero", text, current_bone);
                    return;
                }

                int num = 0;
                Dictionary<string, AnimationCurve> dictionary = null;
                Vector3 vector = Vector3.zero;
                if (isBaseAll && format.motion_list.motion.ContainsKey("全ての親"))
                {
                    vector = format.motion_list.motion["全ての親"][0].location;
                }

                switch (text)
                {
                    case "センター": num = 16; break;
                    case "グルーブ": num = 32; break;
                    case "腰": num = 64; break;
                    case "右足ＩＫ":
                    case "左足ＩＫ":
                        string boneName = text.Substring(0, 2) + "IK親";
                        dictionary = CollectCurve(format, boneName, interpolationQuality);
                        num = 2;
                        break;
                    case "右つま先ＩＫ":
                    case "左つま先ＩＫ": num = 128; break;
                }

                Vector3 vector2 = Vector3.zero;
                if (current_obj != null)
                {
                    vector2 = current_obj.transform.localPosition;
                }

                List<VMDFormat.Motion> list = format.motion_list.motion[text];
                GetKeyframeCount(list, 0, interpolationQuality);
                GetKeyframeCount(list, 1, interpolationQuality);
                GetKeyframeCount(list, 2, interpolationQuality);
                List<FloatKeyframe> keyframes = new List<FloatKeyframe>();
                List<FloatKeyframe> keyframes2 = new List<FloatKeyframe>();
                List<FloatKeyframe> keyframes3 = new List<FloatKeyframe>();
                FloatKeyframe prev_keyframe = null;
                FloatKeyframe prev_keyframe2 = null;
                FloatKeyframe prev_keyframe3 = null;
                int index = 0;
                int index2 = 0;
                int index3 = 0;
                for (int i = 0; i < list.Count; i++)
                {
                    float time = (float)list[i].flame_no / 30f;
                    Vector3 vector3 = list[i].location;
                    if (vector3 == Vector3.zero && num <= 0) continue;
                    if (dictionary != null)
                    {
                        AnimationCurve value = null;
                        dictionary.TryGetValue("localPosition.x", out value);
                        AnimationCurve value2 = null;
                        dictionary.TryGetValue("localPosition.y", out value2);
                        AnimationCurve value3 = null;
                        dictionary.TryGetValue("localPosition.z", out value3);
                        AnimationCurve value4 = null;
                        dictionary.TryGetValue("localEulerAngles.x", out value4);
                        AnimationCurve value5 = null;
                        dictionary.TryGetValue("localEulerAngles.y", out value5);
                        AnimationCurve value6 = null;
                        dictionary.TryGetValue("localEulerAngles.z", out value6);
                        Vector3 vector4 = Vector3.zero;
                        if (value != null && value2 != null && value3 != null)
                        {
                            vector4 = new Vector3(value.Evaluate(time), value2.Evaluate(time), value3.Evaluate(time));
                        }

                        Quaternion rotation = Quaternion.identity;
                        switch (num)
                        {
                            case 1:
                                rotation = list[i].rotation;
                                vector3 += rotation * vector4;
                                break;
                            case 2:
                                if (value4 != null && value5 != null && value6 != null)
                                    rotation = Quaternion.Euler(value4.Evaluate(time), value5.Evaluate(time), value6.Evaluate(time));
                                vector3 = vector4 + rotation * vector3;
                                break;
                        }
                    }

                    if ((num & 0x1F) != 0)
                    {
                        vector3 += vector;
                    }

                    vector3.z = 0f - vector3.z;
                    vector3.x = 0f - vector3.x;
                    if ((num & 0x10) != 0)
                    {
                        vector3 += centerBasePos;
                        if (i == 0)
                        {
                            Console.WriteLine("C:{0},{1},{2}.", vector3.x, vector3.y, vector3.z);
                        }
                    }

                    if ((num & 0x20) != 0)
                    {
                        vector3 += hipPositionDiff;
                        if (i == 0)
                        {
                            Console.WriteLine("S:{0},{1},{2}.", vector3.x, vector3.y, vector3.z);
                        }
                    }

                    if ((num & 0x40) != 0)
                    {
                        if (isUseSlot)
                        {
                            if (i == 0)
                            {
                                Console.WriteLine("H:{0},{1},{2}.", vector3.x, vector3.y, vector3.z);
                            }
                        }
                        else if (centerXCurve != null)
                        {
                            try
                            {
                                float x = centerXCurve.Evaluate(time);
                                float y = centerYCurve.Evaluate(time);
                                float z = centerZCurve.Evaluate(time);
                                float w = centerWCurve.Evaluate(time);
                                Vector3 b = new Quaternion(x, y, z, w) * hipCenterDiff;
                                vector3 = vector3 + b + centerBasePos;
                            }
                            catch (Exception value7)
                            {
                                Console.WriteLine(value7);
                                vector3 = vector3 + hipCenterDiff + centerBasePos;
                            }
                        }
                        else
                        {
                            vector3 = vector3 + hipCenterDiff + centerBasePos;
                        }
                    }

                    switch (text)
                    {
                        case "右足ＩＫ":
                            vector3 += HSModelBaseline.rightFootPos / scale;
                            if (i == 0)
                            {
                                Console.WriteLine("L:{0},{1},{2}.", vector3.x, vector3.y, vector3.z);
                            }

                            break;
                        case "左足ＩＫ":
                            vector3 += HSModelBaseline.leftFootPos / scale;
                            if (i == 0)
                            {
                                Console.WriteLine("R:{0},{1},{2}.", vector3.x, vector3.y, vector3.z);
                            }

                            break;
                        case "右つま先ＩＫ":
                            vector3 += HSModelBaseline.rightToePosRel / scale;
                            break;
                        case "左つま先ＩＫ":
                            vector3 += HSModelBaseline.leftToePosRel / scale;
                            break;
                    }

                    FloatKeyframe floatKeyframe = new FloatKeyframe(time, vector3.x * scale + vector2.x);
                    FloatKeyframe floatKeyframe2 = new FloatKeyframe(time, vector3.y * scale + vector2.y);
                    FloatKeyframe floatKeyframe3 = new FloatKeyframe(time, vector3.z * scale + vector2.z);
                    FloatKeyframe.AddBezierKeyframes(list[i].interpolation, 0, prev_keyframe, floatKeyframe, interpolationQuality, ref keyframes, ref index);
                    FloatKeyframe.AddBezierKeyframes(list[i].interpolation, 1, prev_keyframe2, floatKeyframe2, interpolationQuality, ref keyframes2, ref index2);
                    FloatKeyframe.AddBezierKeyframes(list[i].interpolation, 2, prev_keyframe3, floatKeyframe3, interpolationQuality, ref keyframes3, ref index3);
                    prev_keyframe = floatKeyframe;
                    prev_keyframe2 = floatKeyframe2;
                    prev_keyframe3 = floatKeyframe3;
                }

                FloatKeyframe[] custom_keys = keyframes.ToArray();
                FloatKeyframe[] custom_keys2 = keyframes2.ToArray();
                FloatKeyframe[] custom_keys3 = keyframes3.ToArray();
                if (list.Count != 0)
                {
                    AnimationCurve curve = new AnimationCurve(ToKeyframesForLocation(custom_keys));
                    AnimationCurve curve2 = new AnimationCurve(ToKeyframesForLocation(custom_keys2));
                    AnimationCurve curve3 = new AnimationCurve(ToKeyframesForLocation(custom_keys3));
                    clip.SetCurve(bone_path, typeof(Transform), "localPosition.x", curve);
                    clip.SetCurve(bone_path, typeof(Transform), "localPosition.y", curve2);
                    clip.SetCurve(bone_path, typeof(Transform), "localPosition.z", curve3);
                }
            }
            catch (KeyNotFoundException)
            {
            }
        }

        private Dictionary<string, AnimationCurve> CollectCurve(VMDFormat format, string boneName, int interpolationQuality, Dictionary<string, AnimationCurve> dictionary = null, int flagPos = 1)
        {
            if (!format.motion_list.motion.ContainsKey(boneName))
            {
                return null;
            }

            Dictionary<string, AnimationCurve> dictionary2 = new Dictionary<string, AnimationCurve>();
            List<VMDFormat.Motion> list = format.motion_list.motion[boneName];
            GetKeyframeCount(list, 0, interpolationQuality);
            GetKeyframeCount(list, 1, interpolationQuality);
            GetKeyframeCount(list, 2, interpolationQuality);
            List<FloatKeyframe> keyframes = new List<FloatKeyframe>();
            List<FloatKeyframe> keyframes2 = new List<FloatKeyframe>();
            List<FloatKeyframe> keyframes3 = new List<FloatKeyframe>();
            FloatKeyframe prev_keyframe = null;
            FloatKeyframe prev_keyframe2 = null;
            FloatKeyframe prev_keyframe3 = null;
            int index = 0;
            int index2 = 0;
            int index3 = 0;
            for (int i = 0; i < list.Count; i++)
            {
                float time = (float)list[i].flame_no / 30f;
                Vector3 point = list[i].location;
                if (dictionary != null)
                {
                    AnimationCurve value = null;
                    dictionary.TryGetValue("localPosition.x", out value);
                    AnimationCurve value2 = null;
                    dictionary.TryGetValue("localPosition.y", out value2);
                    AnimationCurve value3 = null;
                    dictionary.TryGetValue("localPosition.z", out value3);
                    AnimationCurve value4 = null;
                    dictionary.TryGetValue("localEulerAngles.x", out value4);
                    AnimationCurve value5 = null;
                    dictionary.TryGetValue("localEulerAngles.y", out value5);
                    AnimationCurve value6 = null;
                    dictionary.TryGetValue("localEulerAngles.z", out value6);
                    Vector3 vector = Vector3.zero;
                    if (value != null && value2 != null && value3 != null)
                    {
                        vector = new Vector3(value.Evaluate(time), value2.Evaluate(time), value3.Evaluate(time));
                    }

                    Quaternion rotation = Quaternion.identity;
                    if (flagPos == 1)
                    {
                        rotation = list[i].rotation;
                        point += rotation * vector;
                    }
                    else
                    {
                        if (value4 != null && value5 != null && value6 != null)
                        {
                            rotation = Quaternion.Euler(value4.Evaluate(time), value5.Evaluate(time), value6.Evaluate(time));
                        }

                        point = vector + rotation * point;
                    }
                }

                FloatKeyframe floatKeyframe = new FloatKeyframe(time, point.x);
                FloatKeyframe floatKeyframe2 = new FloatKeyframe(time, point.y);
                FloatKeyframe floatKeyframe3 = new FloatKeyframe(time, point.z);
                FloatKeyframe.AddBezierKeyframes(list[i].interpolation, 0, prev_keyframe, floatKeyframe, interpolationQuality, ref keyframes, ref index);
                FloatKeyframe.AddBezierKeyframes(list[i].interpolation, 1, prev_keyframe2, floatKeyframe2, interpolationQuality, ref keyframes2, ref index2);
                FloatKeyframe.AddBezierKeyframes(list[i].interpolation, 2, prev_keyframe3, floatKeyframe3, interpolationQuality, ref keyframes3, ref index3);
                prev_keyframe = floatKeyframe;
                prev_keyframe2 = floatKeyframe2;
                prev_keyframe3 = floatKeyframe3;
            }

            if (list.Count != 0)
            {
                FloatKeyframe[] custom_keys = keyframes.ToArray();
                FloatKeyframe[] custom_keys2 = keyframes2.ToArray();
                FloatKeyframe[] custom_keys3 = keyframes3.ToArray();
                AnimationCurve value7 = new AnimationCurve(ToKeyframesForLocation(custom_keys));
                AnimationCurve value8 = new AnimationCurve(ToKeyframesForLocation(custom_keys2));
                AnimationCurve value9 = new AnimationCurve(ToKeyframesForLocation(custom_keys3));
                dictionary2.Add("localPosition.x", value7);
                dictionary2.Add("localPosition.y", value8);
                dictionary2.Add("localPosition.z", value9);
            }

            QuaternionKeyframe[] keyframes4 = new QuaternionKeyframe[GetKeyframeCount(list, 3, interpolationQuality)];
            QuaternionKeyframe prev_keyframe4 = null;
            int index4 = 0;
            for (int j = 0; j < list.Count; j++)
            {
                float time2 = (float)list[j].flame_no / 30f;
                Quaternion rotation2 = list[j].rotation;
                if (dictionary != null)
                {
                    AnimationCurve value10 = null;
                    dictionary.TryGetValue("localEulerAngles.x", out value10);
                    AnimationCurve value11 = null;
                    dictionary.TryGetValue("localEulerAngles.y", out value11);
                    AnimationCurve value12 = null;
                    dictionary.TryGetValue("localEulerAngles.z", out value12);
                    Quaternion identity = Quaternion.identity;
                    if (value10 != null && value11 != null && value12 != null)
                    {
                        identity = Quaternion.Euler(value10.Evaluate(time2), value11.Evaluate(time2), value12.Evaluate(time2));
                        rotation2 *= identity;
                    }
                }

                QuaternionKeyframe quaternionKeyframe = new QuaternionKeyframe(time2, rotation2);
                QuaternionKeyframe.AddBezierKeyframes(list[j].interpolation, 3, prev_keyframe4, quaternionKeyframe, interpolationQuality, ref keyframes4, ref index4);
                prev_keyframe4 = quaternionKeyframe;
            }

            Keyframe[] rx_keys = null;
            Keyframe[] ry_keys = null;
            Keyframe[] rz_keys = null;
            ToKeyframesForRotation(keyframes4, ref rx_keys, ref ry_keys, ref rz_keys);
            AnimationCurve value13 = new AnimationCurve(rx_keys);
            AnimationCurve value14 = new AnimationCurve(ry_keys);
            AnimationCurve value15 = new AnimationCurve(rz_keys);
            dictionary2.Add("localEulerAngles.x", value13);
            dictionary2.Add("localEulerAngles.y", value14);
            dictionary2.Add("localEulerAngles.z", value15);
            return dictionary2;
        }

        private string GetBonePath(Transform transform, Transform root)
        {
            if (transform == root)
            {
                return "";
            }

            if (transform.parent == root)
            {
                return transform.name;
            }

            return GetBonePath(transform.parent, root) + "/" + transform.name;
        }

        private void FullSearchBonePath(Transform root, Transform transform, Dictionary<string, string> dic)
        {
            int childCount = transform.childCount;
            for (int i = 0; i < childCount; i++)
            {
                Transform child = transform.GetChild(i);
                FullSearchBonePath(root, child, dic);
            }

            string bonePath = GetBonePath(transform, root);
            if (dic.ContainsKey(transform.name))
            {
                //_ = dic[transform.name];
            }
            else
            {
                dic.Add(transform.name, bonePath);
            }
        }

        private void FullEntryBoneAnimation(VMDFormat format, AnimationClip clip, Dictionary<string, string> dic, Dictionary<string, GameObject> obj, int interpolationQuality)
        {
            foreach (KeyValuePair<string, string> item in dic)
            {
                GameObject gameObject = null;
                if (obj.ContainsKey(item.Key))
                {
                    gameObject = obj[item.Key];
                    Rigidbody component = gameObject.GetComponent<Rigidbody>();
                    if (component != null && !component.isKinematic) continue;
                }

                CreateKeysForLocation(format, clip, item.Key, item.Value, interpolationQuality, gameObject);
                CreateKeysForRotation(format, clip, item.Key, item.Value, interpolationQuality);
            }
        }

        private void GetGameObjects(Dictionary<string, GameObject> obj, GameObject assign_pmd)
        {
            for (int i = 0; i < assign_pmd.transform.childCount; i++)
            {
                Transform child = assign_pmd.transform.GetChild(i);
                try
                {
                    obj.Add(child.name, child.gameObject);
                }
                catch (ArgumentException ex)
                {
                    Debug.Log(ex.Message);
                    Debug.Log("An element with the same key already exists in the dictionary. -> " + child.name);
                }

                if (!(child == null))
                {
                    GetGameObjects(obj, child.gameObject);
                }
            }
        }
    }
}
